#include "poicheck.h"
#include "ShipManage.h"
#include "LonLatUtil.h"
#include "geographicutil.h"
#include "doublepair.h"
#include "MsgManage.h"
#include "dbdata.h"
#include "WktJson.h"
#include "model/modelriskarea.h"
#include <QDebug>
#include <QtMath>
#include "mylogger.h"

using namespace ns_yht;

PoiCheck *PoiCheck::m_instance = nullptr;

PoiCheck::PoiCheck()
{
    loadFeatures_yhtc();
    m_instance = this;

    // 2-25-06-24 路测，上新城大桥提示桥梁很晚，快下桥才提示
    // Coordinates line{Coordinate(29.9856694444444, 122.182666666667), Coordinate(29.9768333333333, 122.1755)};
    // Coordinates poly{{29.981620146301164, 122.17920077108205}, {29.981249540267843, 122.17890833374447}, {29.98145254766552, 122.17856665983155}, {29.98182315369884, 122.17885909668092}, {29.981620146301164, 122.17920077108205}};
    // bool result = GeographicUtil::intersects_lineToPoly(line, poly);
    // qInfo() << "intersects_lineToPoly================================================================" << result;
}

PoiCheck::~PoiCheck()
{
}

PoiCheck *PoiCheck::instance()
{
    return m_instance;
}

void PoiCheck::check()
{
    check_yhtc();
}

/*
风险区域类型
0	沉船
1	碍航物
2	礁石
3	浅水区
4	商渔船碰撞高发区
5	分道通航区域
6	警戒区
7	禁止抛锚及捕捞区
8	港口
9	跨海桥梁
10	海底管线
11	轮渡航行区
*/

void PoiCheck::check_yhtc()
{
    ModelShip *ownShip = SHIPMANAGE->getOwnShip().data();
    if (!ownShip)
        return;
    bool ownValid = LonLatUtil::isValid(ownShip->lat, ownShip->lon);
    if (!ownValid)
        return;
    const CoordinatesCollection &alertAreas = SHIPMANAGE->getAlertArea();
    if (alertAreas.isEmpty())
        return;
    auto alertArea = alertAreas.at(0);
    if (alertArea.size() < 3)
        return;
    int combinedType = 0;
    if (checkFeatures_yhtc(alertArea, combinedType))
    {
        // ModelMsg中的ID默认值为0，而RiskAreaType是[0,11]，因此这里加1以免查找时判断错误
        for (int i = 0; i <= m_riskareaType_max; i++)
        {
            if (combinedType & (1 << i))
                MSGMANAGE->appendRiskAreaWarning(i + 1);
            else
                MSGMANAGE->cancelRiskAreaWarning(i + 1);
        }
    }
    else
    {
        for (int i = 0; i <= m_riskareaType_max; i++)
            MSGMANAGE->cancelRiskAreaWarning(i + 1);
    }
}

#if 0 // 读取的是TLayer
void PoiCheck::loadFeatures_yhtc()
{
    if (!YHTC)
        return;
    QVector<QSharedPointer<ModelLayer>> layerList;
    if (!DBDATA->getLayerList(layerList, 6))
        return;
    m_features_snroute.clear();
    for (auto &layer : layerList)
    {
        Coordinates coors;
        const QStringList &path = layer->coors.split('|');
        for (int j = 0; j < path.count(); j++)
        {
            const QStringList &scoor = path.at(j).split(',');
            if (scoor.count() != 2)
                continue;
            coors.append(QYHHMap::Coordinate(scoor[1].toDouble(), scoor[0].toDouble()));
        }
        coors.append(coors.first());
        m_features_snroute.append(Feature(Feature::PolygonType, {{coors}}));
    }

    layerList.clear();
    if (!DBDATA->getLayerList(layerList, 5))
        return;
    m_features_collision.clear();
    for (auto &layer : layerList)
    {
        Coordinates coors;
        const QStringList &path = layer->coors.split('|');
        for (int j = 0; j < path.count(); j++)
        {
            const QStringList &scoor = path.at(j).split(',');
            if (scoor.count() != 2)
                continue;
            coors.append(QYHHMap::Coordinate(scoor[1].toDouble(), scoor[0].toDouble()));
        }
        coors.append(coors.first());
        m_features_collision.append(Feature(Feature::PolygonType, {{coors}}));
    }
}
#endif

#if 1 // TRiskArea
void PoiCheck::loadFeatures_yhtc()
{
    QVector<ModelRiskArea> areaList;
    if (!DBDATA->getRiskArea(areaList))
        return;
    m_features_collision.clear();
    m_riskareaTypeList.clear();
    m_riskareaType_max = 0;
    for (auto &area : areaList)
    {
        CoordinatesCollections geom;
        Feature::Type tp = WktJson::parseWkt(area.geom, geom);
        m_features_collision.append(Feature(tp, geom));
        m_riskareaTypeList.append(area.type);
        if (area.type > m_riskareaType_max)
            m_riskareaType_max = area.type;
    }
}
#endif

/**
 * @brief
 *
 * @param alertArea
 * @param shipStatus
 * @param combinedType
 * @return true
 * @return false
 */
bool PoiCheck::checkFeatures_yhtc(const Coordinates &alertArea, int &combinedType)
{
    bool ret = false;
    combinedType = 0;
    ModelShip *ownShip = SHIPMANAGE->getOwnShip().data();
    if (!ownShip)
        return false;
    ShipStatusOfSog shipStatus = ownShip->getStatusOfSog();
#if 0
    foreach (auto &feature, m_features_snroute)
    {
        const Coordinates &polygon = feature.geometry.at(0).at(0);
        if (!GeographicUtil::intersects_polyToPoly(polygon, alertArea))
        {
            ret = true;
            m_features.append(feature);
        }
    }
#endif

    GeographicUtil::setStaticPolygon(alertArea);
    int ccount = 0;
    for (int i = 0, n = m_features_collision.count(); i < n; i++)
    {
        const auto &feature = m_features_collision.at(i);
        int atype = m_riskareaTypeList.at(i);

        // 锚泊状态下只检查管线；航行状态下不检查管线
        if (atype == 10 && shipStatus != ShipStatusOfSog::Anchoring)
            continue;
        else if (atype != 10 && shipStatus == ShipStatusOfSog::Anchoring)
            continue;
        if (feature.type == Feature::PolygonType)
        {
// 一个feature可能有好几个多边形组成，甚至有镂空之类。其实线和点也差不多。这里先简单处理
#if 0
            bool polyIntersects = false;
            foreach (auto &geometries, feature.geometry)
            {
                foreach (auto geom, geometries)
                {
                    if (GeographicUtil::intersects_polyToPoly(geom))
                    {
                        ccount++;
                        ret = true;
                        combinedType |= (1 << atype);
                        m_features.append(feature);
                        polyIntersects = true;
                        break;
                    }
                }
                if (polyIntersects)
                    break;
            }
#else
            if (GeographicUtil::intersects_polyToPoly(feature.geometry.at(0).at(0)))
            {
                ccount++;
                ret = true;
                combinedType |= (1 << atype);
            }
#endif
        }
        else if (feature.type == Feature::LineStringType)
        {
            if (GeographicUtil::intersects_lineToPoly(feature.geometry.at(0).at(0)))
            {
                ccount++;
                ret = true;
                combinedType |= (1 << atype);
            }
        }
        else if (feature.type == Feature::PointType)
        {
            const auto &pt = feature.geometry.at(0).at(0).at(0);
            if (GeographicUtil::pointInGeometry(pt.first, pt.second))
            {
                ccount++;
                ret = true;
                combinedType |= (1 << atype);
            }
        }
    }
    // if (GLOG)
    // GLOG->debug("checkFeatures_yhtc:=============={},{} ", ccount, combinedType);
    return ret;
}
